package com.ruoyi.system.service.impl;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

import com.google.gson.Gson;
import com.jayway.jsonpath.JsonPath;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.sign.Base64;
import com.ruoyi.system.common.SpringContextHolderHandle;
import com.ruoyi.system.domain.IndsvrSsoApp;
import com.ruoyi.system.domain.IndsvrSsoAppAuth;
import com.ruoyi.system.mapper.IndsvrSsoAppMapper;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.sso.SimulationLogin;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

import com.ruoyi.common.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.system.domain.IndsvrSsoAppUserMap;
import com.ruoyi.system.mapper.IndsvrSsoAppUserMapRootMapper;
import com.ruoyi.system.domain.IndsvrSsoAppUserMapRoot;
import com.ruoyi.system.service.IIndsvrSsoAppUserMapRootService;

/**
 * 账号分配Service业务层处理
 * 
 * @author indsvr
 * @date 2025-07-04
 */
@Service
public class IndsvrSsoAppUserMapRootServiceImpl implements IIndsvrSsoAppUserMapRootService 
{
    @Autowired
    private IndsvrSsoAppUserMapRootMapper indsvrSsoAppUserMapRootMapper;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ISysUserService userService;


    @Autowired
    private IndsvrSsoAppMapper indsvrSsoAppMapper;

    /**
     * 查询账号分配
     * 
     * @param id 账号分配主键
     * @return 账号分配
     */
    @Override
    public IndsvrSsoAppUserMapRoot selectIndsvrSsoAppUserMapRootById(Long id)
    {
        return indsvrSsoAppUserMapRootMapper.selectIndsvrSsoAppUserMapRootById(id);
    }

    /**
     * 查询账号分配列表
     * 
     * @param indsvrSsoAppUserMapRoot 账号分配
     * @return 账号分配
     */
    @Override
    public List<IndsvrSsoAppUserMapRoot> selectIndsvrSsoAppUserMapRootList(IndsvrSsoAppUserMapRoot indsvrSsoAppUserMapRoot)
    {
        return indsvrSsoAppUserMapRootMapper.selectIndsvrSsoAppUserMapRootList(indsvrSsoAppUserMapRoot);
    }

    /**
     * 新增账号分配
     * 
     * @param indsvrSsoAppUserMapRoot 账号分配
     * @return 结果
     */
    @Transactional
    @Override
    public int insertIndsvrSsoAppUserMapRoot(IndsvrSsoAppUserMapRoot indsvrSsoAppUserMapRoot)
    {
        indsvrSsoAppUserMapRoot.setCreateTime(DateUtils.getNowDate());
        int rows = indsvrSsoAppUserMapRootMapper.insertIndsvrSsoAppUserMapRoot(indsvrSsoAppUserMapRoot);
        insertIndsvrSsoAppUserMap(indsvrSsoAppUserMapRoot);
        return rows;
    }

    /**
     * 修改账号分配
     * 
     * @param indsvrSsoAppUserMapRoot 账号分配
     * @return 结果
     */
    @Transactional
    @Override
    public int updateIndsvrSsoAppUserMapRoot(IndsvrSsoAppUserMapRoot indsvrSsoAppUserMapRoot)
    {
        indsvrSsoAppUserMapRoot.setUpdateTime(DateUtils.getNowDate());
        indsvrSsoAppUserMapRootMapper.deleteIndsvrSsoAppUserMapByAppId(indsvrSsoAppUserMapRoot.getId());
        insertIndsvrSsoAppUserMap(indsvrSsoAppUserMapRoot);
        return indsvrSsoAppUserMapRootMapper.updateIndsvrSsoAppUserMapRoot(indsvrSsoAppUserMapRoot);
    }

    /**
     * 批量删除账号分配
     * 
     * @param ids 需要删除的账号分配主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteIndsvrSsoAppUserMapRootByIds(Long[] ids)
    {
        indsvrSsoAppUserMapRootMapper.deleteIndsvrSsoAppUserMapByAppIds(ids);
        return indsvrSsoAppUserMapRootMapper.deleteIndsvrSsoAppUserMapRootByIds(ids);
    }

    /**
     * 删除账号分配信息
     * 
     * @param id 账号分配主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteIndsvrSsoAppUserMapRootById(Long id)
    {
        indsvrSsoAppUserMapRootMapper.deleteIndsvrSsoAppUserMapByAppId(id);
        return indsvrSsoAppUserMapRootMapper.deleteIndsvrSsoAppUserMapRootById(id);
    }

    /**
     * 新增用户绑定信息
     * 
     * @param indsvrSsoAppUserMapRoot 账号分配对象
     */
    public void insertIndsvrSsoAppUserMap(IndsvrSsoAppUserMapRoot indsvrSsoAppUserMapRoot)
    {
        List<IndsvrSsoAppUserMap> indsvrSsoAppUserMapList = indsvrSsoAppUserMapRoot.getIndsvrSsoAppUserMapList();
        Long id = indsvrSsoAppUserMapRoot.getId();
        if (StringUtils.isNotNull(indsvrSsoAppUserMapList))
        {
            List<IndsvrSsoAppUserMap> list = new ArrayList<IndsvrSsoAppUserMap>();
            for (IndsvrSsoAppUserMap indsvrSsoAppUserMap : indsvrSsoAppUserMapList)
            {
                indsvrSsoAppUserMap.setAppId(id);
                list.add(indsvrSsoAppUserMap);
            }
            if (list.size() > 0)
            {
                indsvrSsoAppUserMapRootMapper.batchIndsvrSsoAppUserMap(list);
            }
        }
    }

    @Override
    public HashMap<String, String> auth(Long appId, String redirect, String state, SysUser user) {

        IndsvrSsoApp indsvrSsoApp = indsvrSsoAppMapper.selectIndsvrSsoAppById(appId);
        String callbackUrl = indsvrSsoApp.getCallbackUrl();


        if (!callbackUrl.equals(redirect)) {
            throw new RuntimeException("code回调地址不一致");
        }

        String authCode = System.currentTimeMillis() + "." + appId + "." + user.getUserId();
        authCode = Base64.encode(authCode.getBytes(StandardCharsets.UTF_8));


//        authCode =new String(Base64.getDecoder().decode(authCode.getBytes(StandardCharsets.UTF_8)));

        IndsvrSsoAppUserMap indsvrSsoAppUserMap = new IndsvrSsoAppUserMap();
        indsvrSsoAppUserMap.setAppId(appId);
        indsvrSsoAppUserMap.setUserId(user.getUserId());
        List<IndsvrSsoAppUserMap> indsvrSsoAppUserMaps = indsvrSsoAppUserMapRootMapper.selectIndsvrSsoAppUserMapListByBean(indsvrSsoAppUserMap);

        if (indsvrSsoAppUserMaps==null||indsvrSsoAppUserMaps.size()!=1) {
            throw new RuntimeException("映射用户信息不存在或不唯一");
        }
        IndsvrSsoAppUserMap ssoAppUser = indsvrSsoAppUserMaps.get(0);

        ssoAppUser.setAuthCode(authCode);
        ssoAppUser.setRedirect(state);

        indsvrSsoAppUserMapRootMapper.updateIndsvrSsoAppUserMap(ssoAppUser);

        authCode = URLEncoder.encode(authCode, StandardCharsets.UTF_8);

        HashMap<String, String> stringStringHashMap = new HashMap<>();
        stringStringHashMap.put("code",authCode);

        stringStringHashMap.put("redirect",redirect+"?code="+authCode);
        stringStringHashMap.put("state",state);
        return stringStringHashMap;
    }


    @Override
    public long switchSsoType(String code) {

        IndsvrSsoAppUserMap indsvrSsoAppUserMap = new IndsvrSsoAppUserMap();
        indsvrSsoAppUserMap.setAuthCode(code);
        List<IndsvrSsoAppUserMap> indsvrSsoAppUserMaps = indsvrSsoAppUserMapRootMapper.selectIndsvrSsoAppUserMapListByBean(indsvrSsoAppUserMap);
        if (indsvrSsoAppUserMaps==null||indsvrSsoAppUserMaps.size()!=1) {
            throw new RuntimeException("授权吗验证失败");
        }
        IndsvrSsoAppUserMapRoot indsvrSsoAppUserMapRoot = indsvrSsoAppUserMapRootMapper.selectIndsvrSsoAppUserMapRootById(indsvrSsoAppUserMaps.get(0).getAppId());

        return indsvrSsoAppUserMapRoot.getLoginType();
    }

    @Override
    public HashMap<String,Object> accessTokenBy0(String code, HttpServletRequest request) throws Exception{//模拟登录
        IndsvrSsoAppUserMap indsvrSsoAppUserMap = new IndsvrSsoAppUserMap();
        indsvrSsoAppUserMap.setAuthCode(code);
        List<IndsvrSsoAppUserMap> indsvrSsoAppUserMaps = indsvrSsoAppUserMapRootMapper.selectIndsvrSsoAppUserMapListByBean(indsvrSsoAppUserMap);
        if (indsvrSsoAppUserMaps==null||indsvrSsoAppUserMaps.size()!=1) {
            throw new RuntimeException("授权码验证失败");
        }
        IndsvrSsoApp indsvrSsoApp = indsvrSsoAppMapper.selectIndsvrSsoAppById(indsvrSsoAppUserMaps.get(0).getAppId());


        SimulationLogin bean = (SimulationLogin) SpringContextHolderHandle.getBean(Class.forName("com.ruoyi.system.service.sso."+indsvrSsoApp.getLoginFunc()));
        Object invoke = bean.run(indsvrSsoApp, indsvrSsoAppUserMaps.get(0), request);


        List<IndsvrSsoAppAuth> indsvrSsoAppAuthList = indsvrSsoApp.getIndsvrSsoAppAuthList();
        for (IndsvrSsoAppAuth indsvrSsoAppAuth : indsvrSsoAppAuthList) {
            String type = indsvrSsoAppAuth.getType();
            if ("localStorage".equals(type)||"sessionStorage".equals(type)||"cookies".equals(type)||"IndexedDB".equals(type)) {
                Object read = JsonPath.read(new Gson().toJson(invoke), indsvrSsoAppAuth.getAuthValPath());
                String a = read instanceof String ? ((String) read) : new Gson().toJson(read);
                indsvrSsoAppAuth.setAuthValPath(a);
            }

        }
        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        stringObjectHashMap.put("authList",indsvrSsoAppAuthList);
        stringObjectHashMap.put("redirect",indsvrSsoAppUserMaps.get(0).getRedirect());
        return stringObjectHashMap;
    }

    @Override
    public IndsvrSsoAppUserMap accessTokenBy1(String code) {//表单代填

        throw new RuntimeException("尚未实现");
    }

    @Override
    public HashMap<String, Object> accessTokenBy2(String code, String client_secret) {//oauth2
        IndsvrSsoAppUserMap indsvrSsoAppUserMap = new IndsvrSsoAppUserMap();
        indsvrSsoAppUserMap.setAuthCode(code);
        List<IndsvrSsoAppUserMap> indsvrSsoAppUserMaps = indsvrSsoAppUserMapRootMapper.selectIndsvrSsoAppUserMapListByBean(indsvrSsoAppUserMap);
        if (indsvrSsoAppUserMaps==null||indsvrSsoAppUserMaps.size()!=1) {
            throw new RuntimeException("授权吗验证失败");
        }

        HashSet<String> strings = new HashSet<>();
        IndsvrSsoApp indsvrSsoApp = indsvrSsoAppMapper.selectIndsvrSsoAppById(indsvrSsoAppUserMaps.get(0).getAppId());
        for (IndsvrSsoAppAuth indsvrSsoAppAuth : indsvrSsoApp.getIndsvrSsoAppAuthList()) {
            if ("oauth2KV".equals(indsvrSsoAppAuth.getType())) {
                strings.add(indsvrSsoAppAuth.getAuthValPath());
            }
        }

        if (!strings.contains(client_secret)) {
            throw new RuntimeException("client_secret 错误");
        }


        SysUser sysUser = userService.selectUserById(indsvrSsoAppUserMaps.get(0).getUserId());
        sysUser.setUserName(indsvrSsoAppUserMaps.get(0).getUsername());

        String uuid = UUID.randomUUID().toString();

        redisCache.setCacheObject("SSO_KEY:" +uuid,sysUser,1, TimeUnit.MINUTES);

        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        stringObjectHashMap.put("access_token",uuid);
        return stringObjectHashMap;
    }


    @Override
    public String accessTokenBy99(String code, String state, HttpServletRequest request) throws Exception{

        IndsvrSsoApp indsvrSsoApp1 = new IndsvrSsoApp();
        indsvrSsoApp1.setLoginType(99L);
        List<IndsvrSsoApp> indsvrSsoApps = indsvrSsoAppMapper.selectIndsvrSsoAppList(indsvrSsoApp1);
        if (indsvrSsoApps==null||indsvrSsoApps.size()!=1) {
            throw new RuntimeException("被登录配置非唯一");
        }
        IndsvrSsoApp indsvrSsoApp = indsvrSsoApps.get(0);
        indsvrSsoApp = indsvrSsoAppMapper.selectIndsvrSsoAppById(indsvrSsoApp.getId());


        SimulationLogin bean = (SimulationLogin) SpringContextHolderHandle.getBean(Class.forName("com.ruoyi.system.service.sso."+indsvrSsoApp.getLoginFunc()));
        IndsvrSsoAppUserMap user = new IndsvrSsoAppUserMap();
        user.setAuthCode(code);
        user.setState(state);
        Object invoke = bean.run(indsvrSsoApp, user, request);
        String username = (String) invoke;

        IndsvrSsoAppUserMap indsvrSsoAppUserMap = new IndsvrSsoAppUserMap();
        indsvrSsoAppUserMap.setUsername(username);
        indsvrSsoAppUserMap.setAppId(indsvrSsoApp.getId());
        List<IndsvrSsoAppUserMap> indsvrSsoAppUserMaps = indsvrSsoAppUserMapRootMapper.selectIndsvrSsoAppUserMapListByBean(indsvrSsoAppUserMap);
        if (indsvrSsoAppUserMaps==null||indsvrSsoAppUserMaps.size()!=1) {
            throw new RuntimeException("用户映射不唯一");
        }
        IndsvrSsoAppUserMap indsvrSsoAppUserMap1 = indsvrSsoAppUserMaps.get(0);

        String authCode = System.currentTimeMillis() + "." + indsvrSsoAppUserMap1.getUserId() + "." + user.getUserId();
        authCode = Base64.encode(authCode.getBytes(StandardCharsets.UTF_8));

        indsvrSsoAppUserMap1.setAuthCode(authCode);
        indsvrSsoAppUserMap1.setRedirect(state);

        indsvrSsoAppUserMapRootMapper.updateIndsvrSsoAppUserMap(indsvrSsoAppUserMap1);

        return indsvrSsoApp.getCallbackUrl()+"/../../../../ssoLoading.html?code=" + authCode;
//        return indsvrSsoApp.getCallbackUrl()+"/../../../../ssoLoading?code=" + authCode;
    }
}
